iT邦幫忙

2023 iThome 鐵人賽

DAY 19
2
SideProject30

Laravel 擴展宇宙:從 1 到 100 十倍速打造產品獨角獸系列 第 19

#18 準備好出新手村了嗎:Laravel 進階技巧探討 (1/2)

  • 分享至 

  • xImage
  •  

cover

在接下來的 API 開發的中途,我想要提出幾個我在這個專案中有用到的方法,有幾個一定要知道的方法,才能使得專案的推進可以有效率之餘又不會留下太多問題。

Elquent 的 Query Builder

如同我在前面的文章有提到的部分,除了可以遵循 DRY (Don’t Repeat Yourself) 之餘,還可以重組成複雜的查詢邏輯。藉由商業邏輯的組合,去重複使用已經定義好的條件,可以讓你在往後的維護上,可以更好去修改甚至是重構。

Example:

// Channel.php
use App\Models\Builder\ChannelBuilder;
use Illuminate\Database\Eloquent\Builder;

class Channel extends Base
{
    // ...
    public static function query(): ChannelBuilder|Builder
    {
        return parent::query();
    }

    public function newEloquentBuilder($query): ChannelBuilder
    {
        return new ChannelBuilder($query);
    }
    // ...
}

// ChannelBuilder.php
class ChannelBuilder extends Builder
{
    public function isPublished(): self
    {
        return $this->whereStatus(ChannelStatus::published);
    }
}

// Usage
$channel = Channel::query()->isPublished()->find();

Eloquent 的 Event

Eloquent 已經有實作了數個 event ,可以簡單的 hook 特定的 event 去執行一些特別的邏輯,像是:

retrieved, creating, created, updating, updated, saving, saved, deleting, deleted, trashed, forceDeleting, forceDeleted, restoring, restored, and replicating

Ref: https://laravel.com/docs/master/eloquent#events

以下是針對 model 的 primary key 想要改用 uuid 的範例,因為需要先由 application 先產生出 uuid 之後,再寫入到資料庫。另一個原因還有是資料庫尚不支援由 v4 的 uuid 衍生的具有遞增性質的 uuid,所以會需要我們自己產生 uuid。

protected static function boot(): void
{
    parent::boot();

    self::creating(fn (self $model) => $model->{$model->getKeyName()} = (string) Str::orderedUuid());
    self::saving(fn (self $model) => $model->{$model->getKeyName()} = (string) Str::orderedUuid());
}

Note

現在不需要自己管理相關的邏輯,在最新版本的 Laravel 中已經支援 modelprimary key 改用 uuid

class Article extends Model
{
    use HasUuids;
 
    // ...
}

Servcie container

Laravel 中有提供了一個很強大的工具 Servcie container ,運用得當的話可以不僅是享受到依賴反轉(dependency inversion principle)好處,大幅方便測試的撰寫,還可以統一控制 class 的建立用法。

常見的用法如下,由常見的電商多租戶場景為例,我們很容易會需要根據不同的付款方式串接不同第三方支付供應商的 SDK。

PaymentGateway 使用 StripePaymentGateway 來綁定實作的 PaymentGateway

class AppServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->bind(PaymentGateway::class, StripePaymentGateway::class);
    }
}

使用上的話,可以直接使用 type hinet 來讓自動注入的機制知道使用正確的 object。

class OrderController extends Controller
{
    public function getOrder(PaymentGateway $paymentGateway, string $id)
    {
        // ...
        $paymentGateway->getTransactionById($id);
        // ...
    }
}

還可以綁定特定邏輯在 resolving 該 class 時觸發的東西,常見的應該會是 logging 或是 debug 的場景使用。

class AppServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->resolving(StripePaymentGateway::class, fn (StripePaymentGateway $payment) => Log::info(printf('[payment history] action:%s', $payment->action));
    }
}

References


上一篇
#17 用 Colab 打造你的雲端機器學習運算平台 (2/2)
下一篇
#19 準備好出新手村了嗎:Laravel 進階技巧探討 (2/2)
系列文
Laravel 擴展宇宙:從 1 到 100 十倍速打造產品獨角獸30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言